<!DOCTYPE html>



  


<html class="theme-next muse use-motion" lang>
<head><meta name="generator" content="Hexo 3.9.0">
  <meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
<meta name="theme-color" content="#222">









<meta http-equiv="Cache-Control" content="no-transform">
<meta http-equiv="Cache-Control" content="no-siteapp">
















  
  
  <link href="/blog/lib/fancybox/source/jquery.fancybox.css?v=2.1.5" rel="stylesheet" type="text/css">







<link href="/blog/lib/font-awesome/css/font-awesome.min.css?v=4.6.2" rel="stylesheet" type="text/css">

<link href="/blog/css/main.css?v=5.1.4" rel="stylesheet" type="text/css">


  <link rel="apple-touch-icon" sizes="180x180" href="/blog/images/apple-touch-icon-next.png?v=5.1.4">


  <link rel="icon" type="image/png" sizes="32x32" href="/blog/images/favicon-32x32-next.png?v=5.1.4">


  <link rel="icon" type="image/png" sizes="16x16" href="/blog/images/favicon-16x16-next.png?v=5.1.4">


  <link rel="mask-icon" href="/blog/images/logo.svg?v=5.1.4" color="#222">





  <meta name="keywords" content="进阶,">





  <link rel="alternate" href="/blog/atom.xml" title="编程那点事" type="application/atom+xml">






<meta name="description" content="类型别名类型别名用来给一个类型起个新名字。 简单的例子12345678910type Name = string;type NameResolver = () =&amp;gt; string;type NameOrResolver = Name | NameResolver;function getName(n: NameOrResolver): Name &amp;#123;    if (typeof n">
<meta name="keywords" content="进阶">
<meta property="og:type" content="article">
<meta property="og:title" content="TypeScript 进阶篇">
<meta property="og:url" content="https://lhweb.gitee.io/blog/2018/09/27/TypeScript-进阶篇/index.html">
<meta property="og:site_name" content="编程那点事">
<meta property="og:description" content="类型别名类型别名用来给一个类型起个新名字。 简单的例子12345678910type Name = string;type NameResolver = () =&amp;gt; string;type NameOrResolver = Name | NameResolver;function getName(n: NameOrResolver): Name &amp;#123;    if (typeof n">
<meta property="og:locale" content="default">
<meta property="og:updated_time" content="2019-10-03T05:53:45.929Z">
<meta name="twitter:card" content="summary">
<meta name="twitter:title" content="TypeScript 进阶篇">
<meta name="twitter:description" content="类型别名类型别名用来给一个类型起个新名字。 简单的例子12345678910type Name = string;type NameResolver = () =&amp;gt; string;type NameOrResolver = Name | NameResolver;function getName(n: NameOrResolver): Name &amp;#123;    if (typeof n">



<script type="text/javascript" id="hexo.configurations">
  var NexT = window.NexT || {};
  var CONFIG = {
    root: '/blog/',
    scheme: 'Muse',
    version: '5.1.4',
    sidebar: {"position":"left","display":"post","offset":12,"b2t":false,"scrollpercent":false,"onmobile":false},
    fancybox: true,
    tabs: true,
    motion: {"enable":true,"async":false,"transition":{"post_block":"fadeIn","post_header":"slideDownIn","post_body":"slideDownIn","coll_header":"slideLeftIn","sidebar":"slideUpIn"}},
    duoshuo: {
      userId: '0',
      author: 'Author'
    },
    algolia: {
      applicationID: '',
      apiKey: '',
      indexName: '',
      hits: {"per_page":10},
      labels: {"input_placeholder":"Search for Posts","hits_empty":"We didn't find any results for the search: ${query}","hits_stats":"${hits} results found in ${time} ms"}
    }
  };
</script>



  <link rel="canonical" href="https://lhweb.gitee.io/blog/2018/09/27/TypeScript-进阶篇/">





  <title>TypeScript 进阶篇 | 编程那点事</title>
  








</head>

<body itemscope itemtype="http://schema.org/WebPage" lang="default">

  
  
    
  

  <div class="container sidebar-position-left page-post-detail">
    <div class="headband"></div>

    <header id="header" class="header" itemscope itemtype="http://schema.org/WPHeader">
      <div class="header-inner"><div class="site-brand-wrapper">
  <div class="site-meta ">
    

    <div class="custom-logo-site-title">
      <a href="/blog/" class="brand" rel="start">
        <span class="logo-line-before"><i></i></span>
        <span class="site-title">编程那点事</span>
        <span class="logo-line-after"><i></i></span>
      </a>
    </div>
      
        <p class="site-subtitle"></p>
      
  </div>

  <div class="site-nav-toggle">
    <button>
      <span class="btn-bar"></span>
      <span class="btn-bar"></span>
      <span class="btn-bar"></span>
    </button>
  </div>
</div>

<nav class="site-nav">
  

  
    <ul id="menu" class="menu">
      
        
        <li class="menu-item menu-item-home">
          <a href="/blog/" rel="section">
            
              <i class="menu-item-icon fa fa-fw fa-home"></i> <br>
            
            Home
          </a>
        </li>
      
        
        <li class="menu-item menu-item-archives">
          <a href="/blog/archives/" rel="section">
            
              <i class="menu-item-icon fa fa-fw fa-archive"></i> <br>
            
            Archives
          </a>
        </li>
      

      
    </ul>
  

  
</nav>



 </div>
    </header>

    <main id="main" class="main">
      <div class="main-inner">
        <div class="content-wrap">
          <div id="content" class="content">
            

  <div id="posts" class="posts-expand">
    

  

  
  
  

  <article class="post post-type-normal" itemscope itemtype="http://schema.org/Article">
  
  
  
  <div class="post-block">
    <link itemprop="mainEntityOfPage" href="https://lhweb.gitee.io/blog/blog/2018/09/27/TypeScript-进阶篇/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="name" content="lhweb">
      <meta itemprop="description" content>
      <meta itemprop="image" content="/blog/images/avatar.gif">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="编程那点事">
    </span>

    
      <header class="post-header">

        
        
          <h1 class="post-title" itemprop="name headline">TypeScript 进阶篇</h1>
        

        <div class="post-meta">
          <span class="post-time">
            
              <span class="post-meta-item-icon">
                <i class="fa fa-calendar-o"></i>
              </span>
              
                <span class="post-meta-item-text">Posted on</span>
              
              <time title="Post created" itemprop="dateCreated datePublished" datetime="2018-09-27T10:31:37+08:00">
                2018-09-27
              </time>
            

            

            
          </span>

          
            <span class="post-category">
            
              <span class="post-meta-divider">|</span>
            
              <span class="post-meta-item-icon">
                <i class="fa fa-folder-o"></i>
              </span>
              
                <span class="post-meta-item-text">In</span>
              
              
                <span itemprop="about" itemscope itemtype="http://schema.org/Thing">
                  <a href="/blog/categories/typescript/" itemprop="url" rel="index">
                    <span itemprop="name">typescript</span>
                  </a>
                </span>

                
                
              
            </span>
          

          
            
          

          
          

          

          

          

        </div>
      </header>
    

    
    
    
    <div class="post-body" itemprop="articleBody">

      
      

      
        <h1 id="类型别名"><a href="#类型别名" class="headerlink" title="类型别名"></a>类型别名</h1><p>类型别名用来给一个类型起个新名字。</p>
<h2 id="简单的例子"><a href="#简单的例子" class="headerlink" title="简单的例子"></a>简单的例子</h2><figure class="highlight typescript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">type</span> Name = <span class="built_in">string</span>;</span><br><span class="line"><span class="keyword">type</span> NameResolver = <span class="function"><span class="params">()</span> =&gt;</span> <span class="built_in">string</span>;</span><br><span class="line"><span class="keyword">type</span> NameOrResolver = Name | NameResolver;</span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">getName</span>(<span class="params">n: NameOrResolver</span>): <span class="title">Name</span> </span>&#123;</span><br><span class="line">    <span class="keyword">if</span> (<span class="keyword">typeof</span> n === <span class="string">'string'</span>) &#123;</span><br><span class="line">        <span class="keyword">return</span> n;</span><br><span class="line">    &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> n();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>上例中，我们使用 type 创建类型别名。</p>
<p>类型别名常用于联合类型。</p>
<h1 id="字符串字面量类型"><a href="#字符串字面量类型" class="headerlink" title="字符串字面量类型"></a>字符串字面量类型</h1><p>字符串字面量类型用来约束取值只能是某几个字符串中的一个。</p>
<h2 id="简单的例子-1"><a href="#简单的例子-1" class="headerlink" title="简单的例子"></a>简单的例子</h2><figure class="highlight lua"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">type</span> EventNames = <span class="string">'click'</span> | <span class="string">'scroll'</span> | <span class="string">'mousemove'</span>;</span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">handleEvent</span><span class="params">(ele: Element, event: EventNames)</span></span> &#123;</span><br><span class="line">    // <span class="keyword">do</span> something</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">handleEvent(document.getElementById(<span class="string">'hello'</span>), <span class="string">'scroll'</span>);  // 没问题</span><br><span class="line">handleEvent(document.getElementById(<span class="string">'world'</span>), <span class="string">'dbclick'</span>); // 报错，event 不能为 <span class="string">'dbclick'</span></span><br><span class="line"></span><br><span class="line">// index.ts(<span class="number">7</span>,<span class="number">47</span>): <span class="built_in">error</span> TS2345: Argument of <span class="built_in">type</span> <span class="string">'"dbclick"'</span> is <span class="keyword">not</span> assignable to parameter of <span class="built_in">type</span> <span class="string">'EventNames'</span>.</span><br></pre></td></tr></table></figure>
<p>上例中，我们使用 type 定了一个字符串字面量类型 EventNames，它只能取三种字符串中的一种。</p>
<p>注意，类型别名与字符串字面量类型都是使用 type 进行定义。</p>
<h1 id="元组"><a href="#元组" class="headerlink" title="元组"></a>元组</h1><p>数组合并了相同类型的对象，而元组（Tuple）合并了不同类型的对象。</p>
<p>元组起源于函数编程语言（如 F#）,在这些语言中频繁使用元组。</p>
<h2 id="简单的例子-2"><a href="#简单的例子-2" class="headerlink" title="简单的例子"></a>简单的例子</h2><p>定义一对值分别为 string 和 number 的元组：</p>
<p><code>let xcatliu: [string, number] = [&#39;Xcat Liu&#39;, 25];</code></p>
<p>当赋值或访问一个已知索引的元素时，会得到正确的类型：</p>
<figure class="highlight prolog"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">let xcatliu: [string, number];</span><br><span class="line">xcatliu[<span class="number">0</span>] = <span class="string">'Xcat Liu'</span>;</span><br><span class="line">xcatliu[<span class="number">1</span>] = <span class="number">25</span>;</span><br><span class="line"></span><br><span class="line">xcatliu[<span class="number">0</span>].slice(<span class="number">1</span>);</span><br><span class="line">xcatliu[<span class="number">1</span>].toFixed(<span class="number">2</span>);</span><br></pre></td></tr></table></figure>
<p>也可以只赋值其中一项：</p>
<figure class="highlight typescript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> xcatliu: [<span class="built_in">string</span>, <span class="built_in">number</span>];</span><br><span class="line">xcatliu[<span class="number">0</span>] = <span class="string">'Xcat Liu'</span>;</span><br></pre></td></tr></table></figure>
<p>但是当直接对元组类型的变量进行初始化或者赋值的时候，需要提供所有元组类型中指定的项。</p>
<figure class="highlight typescript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> xcatliu: [<span class="built_in">string</span>, <span class="built_in">number</span>];</span><br><span class="line">xcatliu = [<span class="string">'Xcat Liu'</span>, <span class="number">25</span>];</span><br></pre></td></tr></table></figure>
<figure class="highlight vhdl"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">let xcatliu: [<span class="built_in">string</span>, number] = [<span class="symbol">'Xcat</span> Liu'];</span><br><span class="line"></span><br><span class="line">// index.ts(<span class="number">1</span>,<span class="number">5</span>): <span class="literal">error</span> TS2322: <span class="keyword">Type</span> '[<span class="built_in">string</span>]' <span class="keyword">is</span> <span class="keyword">not</span> assignable <span class="keyword">to</span> <span class="keyword">type</span> '[<span class="built_in">string</span>, number]'.</span><br><span class="line">//   <span class="keyword">Property</span> <span class="string">'1'</span> <span class="keyword">is</span> missing <span class="keyword">in</span> <span class="keyword">type</span> '[<span class="built_in">string</span>]'.</span><br></pre></td></tr></table></figure>
<figure class="highlight vhdl"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">let xcatliu: [<span class="built_in">string</span>, number];</span><br><span class="line">xcatliu = [<span class="symbol">'Xcat</span> Liu'];</span><br><span class="line">xcatliu[<span class="number">1</span>] = <span class="number">25</span>;</span><br><span class="line"></span><br><span class="line">// index.ts(<span class="number">2</span>,<span class="number">1</span>): <span class="literal">error</span> TS2322: <span class="keyword">Type</span> '[<span class="built_in">string</span>]' <span class="keyword">is</span> <span class="keyword">not</span> assignable <span class="keyword">to</span> <span class="keyword">type</span> '[<span class="built_in">string</span>, number]'.</span><br><span class="line">//   <span class="keyword">Property</span> <span class="string">'1'</span> <span class="keyword">is</span> missing <span class="keyword">in</span> <span class="keyword">type</span> '[<span class="built_in">string</span>]'.</span><br></pre></td></tr></table></figure>
<h2 id="越界的元素"><a href="#越界的元素" class="headerlink" title="越界的元素"></a>越界的元素</h2><p>当添加越界的元素时，它的类型会被限制为元组中每个类型的联合类型：</p>
<figure class="highlight vhdl"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">let xcatliu: [<span class="built_in">string</span>, number];</span><br><span class="line">xcatliu = [<span class="symbol">'Xcat</span> Liu', <span class="number">25</span>];</span><br><span class="line">xcatliu.push(<span class="symbol">'http</span>://xcatliu.com/');</span><br><span class="line">xcatliu.push(<span class="literal">true</span>);</span><br><span class="line"></span><br><span class="line">// index.ts(<span class="number">4</span>,<span class="number">14</span>): <span class="literal">error</span> TS2345: Argument <span class="keyword">of</span> <span class="keyword">type</span> <span class="symbol">'boolean</span>' <span class="keyword">is</span> <span class="keyword">not</span> assignable <span class="keyword">to</span> <span class="keyword">parameter</span> <span class="keyword">of</span> <span class="keyword">type</span> <span class="symbol">'string</span> | number'.</span><br><span class="line">//   <span class="keyword">Type</span> <span class="symbol">'boolean</span>' <span class="keyword">is</span> <span class="keyword">not</span> assignable <span class="keyword">to</span> <span class="keyword">type</span> <span class="symbol">'number</span>'.</span><br></pre></td></tr></table></figure>
<h1 id="枚举"><a href="#枚举" class="headerlink" title="枚举"></a>枚举</h1><p>枚举（Enum）类型用于取值被限定在一定范围内的场景，比如一周只能有七天，颜色限定为红绿蓝等。</p>
<h2 id="简单的例子-3"><a href="#简单的例子-3" class="headerlink" title="简单的例子"></a>简单的例子</h2><p>枚举使用 <strong>enum</strong> 关键字来定义：</p>
<p><code>enum Days {Sun, Mon, Tue, Wed, Thu, Fri, Sat};</code></p>
<p>枚举成员会被赋值为从 0 开始递增的数字，同时也会对枚举值到枚举名进行反向映射：</p>
<figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">enum</span> Days &#123;Sun, Mon, Tue, Wed, Thu, Fri, Sat&#125;;</span><br><span class="line"></span><br><span class="line">console.<span class="built_in">log</span>(Days[<span class="string">"Sun"</span>] === <span class="number">0</span>); <span class="comment">// true</span></span><br><span class="line">console.<span class="built_in">log</span>(Days[<span class="string">"Mon"</span>] === <span class="number">1</span>); <span class="comment">// true</span></span><br><span class="line">console.<span class="built_in">log</span>(Days[<span class="string">"Tue"</span>] === <span class="number">2</span>); <span class="comment">// true</span></span><br><span class="line">console.<span class="built_in">log</span>(Days[<span class="string">"Sat"</span>] === <span class="number">6</span>); <span class="comment">// true</span></span><br><span class="line"></span><br><span class="line">console.<span class="built_in">log</span>(Days[<span class="number">0</span>] === <span class="string">"Sun"</span>); <span class="comment">// true</span></span><br><span class="line">console.<span class="built_in">log</span>(Days[<span class="number">1</span>] === <span class="string">"Mon"</span>); <span class="comment">// true</span></span><br><span class="line">console.<span class="built_in">log</span>(Days[<span class="number">2</span>] === <span class="string">"Tue"</span>); <span class="comment">// true</span></span><br><span class="line">console.<span class="built_in">log</span>(Days[<span class="number">6</span>] === <span class="string">"Sat"</span>); <span class="comment">// true</span></span><br></pre></td></tr></table></figure>
<p>事实上，上面的例子会被编译为：</p>
<figure class="highlight excel"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">var</span> <span class="built_in">Days</span>;</span><br><span class="line">(function (<span class="built_in">Days</span>) &#123;</span><br><span class="line">    <span class="built_in">Days</span>[<span class="built_in">Days</span>[<span class="string">"Sun"</span>] = <span class="number">0</span>] = <span class="string">"Sun"</span>;</span><br><span class="line">    <span class="built_in">Days</span>[<span class="built_in">Days</span>[<span class="string">"Mon"</span>] = <span class="number">1</span>] = <span class="string">"Mon"</span>;</span><br><span class="line">    <span class="built_in">Days</span>[<span class="built_in">Days</span>[<span class="string">"Tue"</span>] = <span class="number">2</span>] = <span class="string">"Tue"</span>;</span><br><span class="line">    <span class="built_in">Days</span>[<span class="built_in">Days</span>[<span class="string">"Wed"</span>] = <span class="number">3</span>] = <span class="string">"Wed"</span>;</span><br><span class="line">    <span class="built_in">Days</span>[<span class="built_in">Days</span>[<span class="string">"Thu"</span>] = <span class="number">4</span>] = <span class="string">"Thu"</span>;</span><br><span class="line">    <span class="built_in">Days</span>[<span class="built_in">Days</span>[<span class="string">"Fri"</span>] = <span class="number">5</span>] = <span class="string">"Fri"</span>;</span><br><span class="line">    <span class="built_in">Days</span>[<span class="built_in">Days</span>[<span class="string">"Sat"</span>] = <span class="number">6</span>] = <span class="string">"Sat"</span>;</span><br><span class="line">&#125;)(<span class="built_in">Days</span> || (<span class="built_in">Days</span> = &#123;&#125;));</span><br></pre></td></tr></table></figure>
<h2 id="手动赋值"><a href="#手动赋值" class="headerlink" title="手动赋值"></a>手动赋值</h2><p>我们也可以给枚举项手动赋值：</p>
<figure class="highlight lsl"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">enum Days &#123;Sun = <span class="number">7</span>, Mon = <span class="number">1</span>, Tue, Wed, Thu, Fri, Sat&#125;;</span><br><span class="line"></span><br><span class="line">console.log(Days[<span class="string">"Sun"</span>] === <span class="number">7</span>); <span class="comment">// true</span></span><br><span class="line">console.log(Days[<span class="string">"Mon"</span>] === <span class="number">1</span>); <span class="comment">// true</span></span><br><span class="line">console.log(Days[<span class="string">"Tue"</span>] === <span class="number">2</span>); <span class="comment">// true</span></span><br><span class="line">console.log(Days[<span class="string">"Sat"</span>] === <span class="number">6</span>); <span class="comment">// true</span></span><br></pre></td></tr></table></figure>
<p>上面的例子中，未手动赋值的枚举项会接着上一个枚举项递增。</p>
<p>如果未手动赋值的枚举项与手动赋值的重复了，TypeScript 是不会察觉到这一点的：</p>
<figure class="highlight lsl"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">enum Days &#123;Sun = <span class="number">3</span>, Mon = <span class="number">1</span>, Tue, Wed, Thu, Fri, Sat&#125;;</span><br><span class="line"></span><br><span class="line">console.log(Days[<span class="string">"Sun"</span>] === <span class="number">3</span>); <span class="comment">// true</span></span><br><span class="line">console.log(Days[<span class="string">"Wed"</span>] === <span class="number">3</span>); <span class="comment">// true</span></span><br><span class="line">console.log(Days[<span class="number">3</span>] === <span class="string">"Sun"</span>); <span class="comment">// false</span></span><br><span class="line">console.log(Days[<span class="number">3</span>] === <span class="string">"Wed"</span>); <span class="comment">// true</span></span><br></pre></td></tr></table></figure>
<p>上面的例子中，递增到 3 的时候与前面的 Sun 的取值重复了，但是 TypeScript 并没有报错，导致 Days[3] 的值先是 “Sun”，而后又被 “Wed” 覆盖了。编译的结果是：</p>
<figure class="highlight excel"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">var</span> <span class="built_in">Days</span>;</span><br><span class="line">(function (<span class="built_in">Days</span>) &#123;</span><br><span class="line">    <span class="built_in">Days</span>[<span class="built_in">Days</span>[<span class="string">"Sun"</span>] = <span class="number">3</span>] = <span class="string">"Sun"</span>;</span><br><span class="line">    <span class="built_in">Days</span>[<span class="built_in">Days</span>[<span class="string">"Mon"</span>] = <span class="number">1</span>] = <span class="string">"Mon"</span>;</span><br><span class="line">    <span class="built_in">Days</span>[<span class="built_in">Days</span>[<span class="string">"Tue"</span>] = <span class="number">2</span>] = <span class="string">"Tue"</span>;</span><br><span class="line">    <span class="built_in">Days</span>[<span class="built_in">Days</span>[<span class="string">"Wed"</span>] = <span class="number">3</span>] = <span class="string">"Wed"</span>;</span><br><span class="line">    <span class="built_in">Days</span>[<span class="built_in">Days</span>[<span class="string">"Thu"</span>] = <span class="number">4</span>] = <span class="string">"Thu"</span>;</span><br><span class="line">    <span class="built_in">Days</span>[<span class="built_in">Days</span>[<span class="string">"Fri"</span>] = <span class="number">5</span>] = <span class="string">"Fri"</span>;</span><br><span class="line">    <span class="built_in">Days</span>[<span class="built_in">Days</span>[<span class="string">"Sat"</span>] = <span class="number">6</span>] = <span class="string">"Sat"</span>;</span><br><span class="line">&#125;)(<span class="built_in">Days</span> || (<span class="built_in">Days</span> = &#123;&#125;));</span><br></pre></td></tr></table></figure>
<p>所以使用的时候需要注意，最好不要出现这种覆盖的情况。</p>
<p>手动赋值的枚举项可以不是数字，此时需要使用类型断言来让tsc无视类型检查 (编译出的js仍然是可用的)：</p>
<figure class="highlight capnproto"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">enum</span> <span class="title">Days</span> </span>&#123;Sun = <span class="number">7</span>, Mon, Tue, Wed, Thu, Fri, Sat = &lt;any&gt;<span class="string">"S"</span>&#125;;</span><br></pre></td></tr></table></figure>
<figure class="highlight excel"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">var</span> <span class="built_in">Days</span>;</span><br><span class="line">(function (<span class="built_in">Days</span>) &#123;</span><br><span class="line">    <span class="built_in">Days</span>[<span class="built_in">Days</span>[<span class="string">"Sun"</span>] = <span class="number">7</span>] = <span class="string">"Sun"</span>;</span><br><span class="line">    <span class="built_in">Days</span>[<span class="built_in">Days</span>[<span class="string">"Mon"</span>] = <span class="number">8</span>] = <span class="string">"Mon"</span>;</span><br><span class="line">    <span class="built_in">Days</span>[<span class="built_in">Days</span>[<span class="string">"Tue"</span>] = <span class="number">9</span>] = <span class="string">"Tue"</span>;</span><br><span class="line">    <span class="built_in">Days</span>[<span class="built_in">Days</span>[<span class="string">"Wed"</span>] = <span class="number">10</span>] = <span class="string">"Wed"</span>;</span><br><span class="line">    <span class="built_in">Days</span>[<span class="built_in">Days</span>[<span class="string">"Thu"</span>] = <span class="number">11</span>] = <span class="string">"Thu"</span>;</span><br><span class="line">    <span class="built_in">Days</span>[<span class="built_in">Days</span>[<span class="string">"Fri"</span>] = <span class="number">12</span>] = <span class="string">"Fri"</span>;</span><br><span class="line">    <span class="built_in">Days</span>[<span class="built_in">Days</span>[<span class="string">"Sat"</span>] = <span class="string">"S"</span>] = <span class="string">"Sat"</span>;</span><br><span class="line">&#125;)(<span class="built_in">Days</span> || (<span class="built_in">Days</span> = &#123;&#125;));</span><br></pre></td></tr></table></figure>
<p>当然，手动赋值的枚举项也可以为小数或负数，此时后续未手动赋值的项的递增步长仍为 1：</p>
<figure class="highlight lsl"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">enum Days &#123;Sun = <span class="number">7</span>, Mon = <span class="number">1.5</span>, Tue, Wed, Thu, Fri, Sat&#125;;</span><br><span class="line"></span><br><span class="line">console.log(Days[<span class="string">"Sun"</span>] === <span class="number">7</span>); <span class="comment">// true</span></span><br><span class="line">console.log(Days[<span class="string">"Mon"</span>] === <span class="number">1.5</span>); <span class="comment">// true</span></span><br><span class="line">console.log(Days[<span class="string">"Tue"</span>] === <span class="number">2.5</span>); <span class="comment">// true</span></span><br><span class="line">console.log(Days[<span class="string">"Sat"</span>] === <span class="number">6.5</span>); <span class="comment">// true</span></span><br></pre></td></tr></table></figure>
<h2 id="常数项和计算所得项"><a href="#常数项和计算所得项" class="headerlink" title="常数项和计算所得项"></a>常数项和计算所得项</h2><p>枚举项有两种类型：常数项（constant member）和计算所得项（computed member）。</p>
<p>前面我们所举的例子都是常数项，一个典型的计算所得项的例子：</p>
<figure class="highlight capnproto"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">enum</span> <span class="title">Color</span> </span>&#123;Red, Green, Blue = <span class="string">"blue"</span>.length&#125;;</span><br></pre></td></tr></table></figure>
<p>上面的例子中，”blue”.length 就是一个计算所得项。</p>
<p>上面的例子不会报错，但是如果紧接在计算所得项后面的是未手动赋值的项，那么它就会因为无法获得初始值而报错：</p>
<figure class="highlight maxima"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">enum Color &#123;Red = <span class="string">"red"</span>.<span class="built_in">length</span>, Green, Blue&#125;;</span><br><span class="line"></span><br><span class="line">// index.ts(<span class="number">1</span>,<span class="number">33</span>): <span class="built_in">error</span> TS1061: Enum <span class="built_in">member</span> must have initializer.</span><br><span class="line">// index.ts(<span class="number">1</span>,<span class="number">40</span>): <span class="built_in">error</span> TS1061: Enum <span class="built_in">member</span> must have initializer.</span><br></pre></td></tr></table></figure>
<p>下面是常数项和计算所得项的完整定义，部分引用自中文手册 - 枚举：</p>
<p>当满足以下条件时，枚举成员被当作是常数：</p>
<ul>
<li>不具有初始化函数并且之前的枚举成员是常数。在这种情况下，当前枚举成员的值为上一个枚举成员的值加 1。但第一个枚举元素是个例外。如果它没有初始化方法，那么它的初始值为 0。</li>
<li>枚举成员使用常数枚举表达式初始化。常数枚举表达式是 TypeScript 表达式的子集，它可以在编译阶段求值。当一个表达式满足下面条件之一时，它就是一个常数枚举表达式：<ul>
<li>数字字面量</li>
<li>引用之前定义的常数枚举成员（可以是在不同的枚举类型中定义的）如果这个成员是在同一个枚举类型中定义的，可以使用非限定名来引用</li>
<li>带括号的常数枚举表达式</li>
<li>+, -, ~ 一元运算符应用于常数枚举表达式</li>
<li>+, -, *, /, %, &lt;&lt;, &gt;&gt;, &gt;&gt;&gt;, &amp;, |, ^ 二元运算符，常数枚举表达式做为其一个操作对象。若常数枚举表达式求值后为NaN或Infinity，则会在编译阶段报错</li>
</ul>
</li>
</ul>
<p>所有其它情况的枚举成员被当作是需要计算得出的值。</p>
<h2 id="常数枚举"><a href="#常数枚举" class="headerlink" title="常数枚举"></a>常数枚举</h2><p>常数枚举是使用 <strong>const enum</strong> 定义的枚举类型：</p>
<figure class="highlight crystal"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">const <span class="class"><span class="keyword">enum</span> <span class="title">Directions</span> &#123;</span></span><br><span class="line">    Up,</span><br><span class="line">    Down,</span><br><span class="line">    Left,</span><br><span class="line">    Right</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">let directions = [Directions.Up, Directions.Down, Directions.Left, Directions.Right];</span><br></pre></td></tr></table></figure>
<p>常数枚举与普通枚举的区别是，它会在编译阶段被删除，并且不能包含计算成员。</p>
<p>上例的编译结果是：</p>
<p><code>var directions = [0 /* Up */, 1 /* Down */, 2 /* Left */, 3 /* Right */];</code></p>
<p>假如包含了计算成员，则会在编译阶段报错：</p>
<figure class="highlight capnproto"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> <span class="class"><span class="keyword">enum</span> <span class="title">Color</span> </span>&#123;Red, Green, Blue = <span class="string">"blue"</span>.length&#125;;</span><br><span class="line"></span><br><span class="line">// index.ts(<span class="number">1</span>,<span class="number">38</span>): error TS2474: In '<span class="keyword">const</span>' <span class="class"><span class="keyword">enum</span> <span class="title">declarations</span> member initializer must be constant expression.</span></span><br></pre></td></tr></table></figure>
<h2 id="外部枚举"><a href="#外部枚举" class="headerlink" title="外部枚举"></a>外部枚举</h2><p>外部枚举（Ambient Enums）是使用 <strong>declare enum</strong> 定义的枚举类型：</p>
<figure class="highlight crystal"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">declare <span class="class"><span class="keyword">enum</span> <span class="title">Directions</span> &#123;</span></span><br><span class="line">    Up,</span><br><span class="line">    Down,</span><br><span class="line">    Left,</span><br><span class="line">    Right</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">let directions = [Directions.Up, Directions.Down, Directions.Left, Directions.Right];</span><br></pre></td></tr></table></figure>
<p>之前提到过，<strong>declare</strong> 定义的类型只会用于编译时的检查，编译结果中会被删除。</p>
<p>上例的编译结果是：<br><figure class="highlight mathematica"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">var directions = [Directions.<span class="keyword">Up</span>, Directions.<span class="keyword">Down</span>, Directions.<span class="keyword">Left</span>, Directions.<span class="keyword">Right</span>];</span><br></pre></td></tr></table></figure></p>
<p>外部枚举与声明语句一样，常出现在声明文件中。</p>
<p>同时使用 <strong>declare</strong> 和 <strong>const</strong> 也是可以的：<br><figure class="highlight crystal"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">declare const <span class="class"><span class="keyword">enum</span> <span class="title">Directions</span> &#123;</span></span><br><span class="line">    Up,</span><br><span class="line">    Down,</span><br><span class="line">    Left,</span><br><span class="line">    Right</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">let directions = [Directions.Up, Directions.Down, Directions.Left, Directions.Right];</span><br></pre></td></tr></table></figure></p>
<p>编译结果：<br><figure class="highlight lsl"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">var directions = [<span class="number">0</span> <span class="comment">/* Up */</span>, <span class="number">1</span> <span class="comment">/* Down */</span>, <span class="number">2</span> <span class="comment">/* Left */</span>, <span class="number">3</span> <span class="comment">/* Right */</span>];</span><br></pre></td></tr></table></figure></p>
<p>TypeScript 的枚举类型的概念来源于 C#。</p>
<h1 id="类"><a href="#类" class="headerlink" title="类"></a>类</h1><p>传统方法中，JavaScript 通过构造函数实现类的概念，通过原型链实现继承。而在 ES6 中，我们终于迎来了 class。</p>
<p>TypeScript 除了实现了所有 ES6 中的类的功能以外，还添加了一些新的用法。</p>
<p>这一节主要介绍类的用法，下一节再介绍如何定义类的类型。</p>
<h2 id="类的概念"><a href="#类的概念" class="headerlink" title="类的概念"></a>类的概念</h2><p>虽然 JavaScript 中有类的概念，但是可能大多数 JavaScript 程序员并不是非常熟悉类，这里对类相关的概念做一个简单的介绍。</p>
<ul>
<li>类(Class)：定义了一件事物的抽象特点，包含它的属性和方法</li>
<li>对象（Object）：类的实例，通过 new 生成</li>
<li>面向对象（OOP）的三大特性：封装、继承、多态</li>
<li>封装（Encapsulation）：将对数据的操作细节隐藏起来，只暴露对外的接口。外界调用端不需要（也不可能）知道细节，就能通过对外提供的接口来访问该对象，同时也保证了外界无法任意更改对象内部的数据</li>
<li>继承（Inheritance）：子类继承父类，子类除了拥有父类的所有特性外，还有一些更具体的特性</li>
<li>多态（Polymorphism）：由继承而产生了相关的不同的类，对同一个方法可以有不同的响应。比如 Cat 和 Dog 都继承自 Animal，但是分别实现了自己的 eat 方法。此时针对某一个实例，我们无需了解它是 Cat 还是 Dog，就可以直接调用 eat 方法，程序会自动判断出来应该如何执行 eat</li>
<li>存取器（getter &amp; setter）：用以改变属性的读取和赋值行为</li>
<li>修饰符（Modifiers）：修饰符是一些关键字，用于限定成员或类型的性质。比如 public 表示公有属性或方法</li>
<li>抽象类（Abstract Class）：抽象类是供其他类继承的基类，抽象类不允许被实例化。抽象类中的抽象方法必须在子类中被实现</li>
<li>接口（Interfaces）：不同类之间公有的属性或方法，可以抽象成一个接口。接口可以被类实现（implements）。一个类只能继承自另一个类，但是可以实现多个接口</li>
</ul>
<h2 id="ES6-中类的用法"><a href="#ES6-中类的用法" class="headerlink" title="ES6 中类的用法"></a>ES6 中类的用法</h2><p>下面我们先回顾一下 ES6 中类的用法，更详细的介绍可以参考 ECMAScript 6 入门 - Class。</p>
<h3 id="属性和方法"><a href="#属性和方法" class="headerlink" title="属性和方法"></a>属性和方法</h3><p>使用 class 定义类，使用 constructor 定义构造函数。</p>
<p>通过 new 生成新实例的时候，会自动调用构造函数。</p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Animal</span> </span>&#123;</span><br><span class="line">    <span class="keyword">constructor</span>(name) &#123;</span><br><span class="line">        <span class="keyword">this</span>.name = name;</span><br><span class="line">    &#125;</span><br><span class="line">    sayHi() &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="string">`My name is <span class="subst">$&#123;<span class="keyword">this</span>.name&#125;</span>`</span>;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> a = <span class="keyword">new</span> Animal(<span class="string">'Jack'</span>);</span><br><span class="line"><span class="built_in">console</span>.log(a.sayHi()); <span class="comment">// My name is Jack</span></span><br></pre></td></tr></table></figure>
<h3 id="类的继承"><a href="#类的继承" class="headerlink" title="类的继承"></a>类的继承</h3><p>使用 extends 关键字实现继承，子类中使用 super 关键字来调用父类的构造函数和方法。</p>
<figure class="highlight scala"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Cat</span> <span class="keyword">extends</span> <span class="title">Animal</span> </span>&#123;</span><br><span class="line">    constructor(name) &#123;</span><br><span class="line">        <span class="keyword">super</span>(name); <span class="comment">// 调用父类的 constructor(name)</span></span><br><span class="line">        console.log(<span class="keyword">this</span>.name);</span><br><span class="line">    &#125;</span><br><span class="line">    sayHi() &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="symbol">'Meow</span>, ' + <span class="keyword">super</span>.sayHi(); <span class="comment">// 调用父类的 sayHi()</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">let c = <span class="keyword">new</span> <span class="type">Cat</span>(<span class="symbol">'To</span>m'); <span class="comment">// Tom</span></span><br><span class="line">console.log(c.sayHi()); <span class="comment">// Meow, My name is Tom</span></span><br></pre></td></tr></table></figure>
<h3 id="存取器"><a href="#存取器" class="headerlink" title="存取器"></a>存取器</h3><p>使用 <strong>getter</strong> 和 <strong>setter</strong> 可以改变属性的赋值和读取行为：</p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Animal</span> </span>&#123;</span><br><span class="line">    <span class="keyword">constructor</span>(name) &#123;</span><br><span class="line">        <span class="keyword">this</span>.name = name;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">get</span> name() &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="string">'Jack'</span>;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">set</span> name(value) &#123;</span><br><span class="line">        <span class="built_in">console</span>.log(<span class="string">'setter: '</span> + value);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> a = <span class="keyword">new</span> Animal(<span class="string">'Kitty'</span>); <span class="comment">// setter: Kitty</span></span><br><span class="line">a.name = <span class="string">'Tom'</span>; <span class="comment">// setter: Tom</span></span><br><span class="line"><span class="built_in">console</span>.log(a.name); <span class="comment">// Jack</span></span><br></pre></td></tr></table></figure>
<h3 id="静态方法"><a href="#静态方法" class="headerlink" title="静态方法"></a>静态方法</h3><p>使用 <strong>static</strong> 修饰符修饰的方法称为静态方法，它们不需要实例化，而是直接通过类来调用：</p>
<figure class="highlight cs"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title">Animal</span> &#123;</span><br><span class="line">    <span class="function"><span class="keyword">static</span> <span class="title">isAnimal</span>(<span class="params">a</span>)</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> a instanceof Animal;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> a = <span class="keyword">new</span> Animal(<span class="string">'Jack'</span>);</span><br><span class="line">Animal.isAnimal(a); <span class="comment">// true</span></span><br><span class="line">a.isAnimal(a); <span class="comment">// TypeError: a.isAnimal is not a function</span></span><br></pre></td></tr></table></figure>
<h2 id="ES7-中类的用法"><a href="#ES7-中类的用法" class="headerlink" title="ES7 中类的用法"></a>ES7 中类的用法</h2><p>ES7 中有一些关于类的提案，TypeScript 也实现了它们，这里做一个简单的介绍。</p>
<h3 id="实例属性"><a href="#实例属性" class="headerlink" title="实例属性"></a>实例属性</h3><p>ES6 中实例的属性只能通过构造函数中的 this.xxx 来定义，ES7 提案中可以直接在类里面定义：</p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Animal</span> </span>&#123;</span><br><span class="line">    name = <span class="string">'Jack'</span>;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">constructor</span>() &#123;</span><br><span class="line">        <span class="comment">// ...</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> a = <span class="keyword">new</span> Animal();</span><br><span class="line"><span class="built_in">console</span>.log(a.name); <span class="comment">// Jack</span></span><br></pre></td></tr></table></figure>
<h3 id="静态属性"><a href="#静态属性" class="headerlink" title="静态属性"></a>静态属性</h3><p>ES7 提案中，可以使用 <strong>static</strong> 定义一个静态属性：</p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Animal</span> </span>&#123;</span><br><span class="line">    <span class="keyword">static</span> num = <span class="number">42</span>;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">constructor</span>() &#123;</span><br><span class="line">        <span class="comment">// ...</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="built_in">console</span>.log(Animal.num); <span class="comment">// 42</span></span><br></pre></td></tr></table></figure>
<h2 id="TypeScript-中类的用法"><a href="#TypeScript-中类的用法" class="headerlink" title="TypeScript 中类的用法"></a>TypeScript 中类的用法</h2><h3 id="public-private-和-protected"><a href="#public-private-和-protected" class="headerlink" title="public private 和 protected"></a>public private 和 protected</h3><p>TypeScript 可以使用三种访问修饰符（Access Modifiers），分别是 public、private 和 protected。</p>
<ul>
<li>public 修饰的属性或方法是公有的，可以在任何地方被访问到，默认所有的属性和方法都是 public 的</li>
<li>private 修饰的属性或方法是私有的，不能在声明它的类的外部访问</li>
<li>protected 修饰的属性或方法是受保护的，它和 private 类似，区别是它在子类中也是允许被访问的</li>
</ul>
<p>下面举一些例子：</p>
<figure class="highlight typescript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> Animal &#123;</span><br><span class="line">    <span class="keyword">public</span> name;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">constructor</span>(<span class="params">name</span>) &#123;</span><br><span class="line">        <span class="keyword">this</span>.name = name;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> a = <span class="keyword">new</span> Animal(<span class="string">'Jack'</span>);</span><br><span class="line"><span class="built_in">console</span>.log(a.name); <span class="comment">// Jack</span></span><br><span class="line">a.name = <span class="string">'Tom'</span>;</span><br><span class="line"><span class="built_in">console</span>.log(a.name); <span class="comment">// Tom</span></span><br></pre></td></tr></table></figure>
<p>上面的例子中，name 被设置为了 public，所以直接访问实例的 name 属性是允许的。</p>
<p>很多时候，我们希望有的属性是无法直接存取的，这时候就可以用 private 了：</p>
<figure class="highlight xquery"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line">class Animal &#123;</span><br><span class="line">    private<span class="built_in"> name</span>;</span><br><span class="line">    public constructor<span class="built_in">(name</span>) &#123;</span><br><span class="line">        this<span class="built_in">.name</span> =<span class="built_in"> name</span>;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> a = new Animal(<span class="string">'Jack'</span>);</span><br><span class="line">console.log(a<span class="built_in">.name</span>); // Jack</span><br><span class="line">a<span class="built_in">.name</span> = <span class="string">'Tom'</span>;</span><br><span class="line"></span><br><span class="line">// index.ts(<span class="number">9</span>,<span class="number">13</span>):<span class="built_in"> error</span> TS2341: Property <span class="string">'name'</span> <span class="literal">is</span> private <span class="keyword">and</span> <span class="keyword">only</span> accessible within class <span class="string">'Animal'</span>.</span><br><span class="line">// index.ts(<span class="number">10</span>,<span class="number">1</span>):<span class="built_in"> error</span> TS2341: Property <span class="string">'name'</span> <span class="literal">is</span> private <span class="keyword">and</span> <span class="keyword">only</span> accessible within class <span class="string">'Animal'</span>.</span><br></pre></td></tr></table></figure>
<p>需要注意的是，TypeScript 编译之后的代码中，并没有限制 private 属性在外部的可访问性。</p>
<p>上面的例子编译后的代码是：</p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> Animal = (<span class="function"><span class="keyword">function</span> (<span class="params"></span>) </span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">function</span> <span class="title">Animal</span>(<span class="params">name</span>) </span>&#123;</span><br><span class="line">        <span class="keyword">this</span>.name = name;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> Animal;</span><br><span class="line">&#125;());</span><br><span class="line"><span class="keyword">var</span> a = <span class="keyword">new</span> Animal(<span class="string">'Jack'</span>);</span><br><span class="line"><span class="built_in">console</span>.log(a.name);</span><br><span class="line">a.name = <span class="string">'Tom'</span>;</span><br></pre></td></tr></table></figure>
<p>使用 private 修饰的属性或方法，在子类中也是不允许访问的：</p>
<figure class="highlight scala"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Animal</span> </span>&#123;</span><br><span class="line">    <span class="keyword">private</span> name;</span><br><span class="line">    public constructor(name) &#123;</span><br><span class="line">        <span class="keyword">this</span>.name = name;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Cat</span> <span class="keyword">extends</span> <span class="title">Animal</span> </span>&#123;</span><br><span class="line">    constructor(name) &#123;</span><br><span class="line">        <span class="keyword">super</span>(name);</span><br><span class="line">        console.log(<span class="keyword">this</span>.name);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// index.ts(11,17): error TS2341: Property 'name' is private and only accessible within class 'Animal'.</span></span><br></pre></td></tr></table></figure>
<p>而如果是用 protected 修饰，则允许在子类中访问：</p>
<figure class="highlight scala"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Animal</span> </span>&#123;</span><br><span class="line">    <span class="keyword">protected</span> name;</span><br><span class="line">    public constructor(name) &#123;</span><br><span class="line">        <span class="keyword">this</span>.name = name;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Cat</span> <span class="keyword">extends</span> <span class="title">Animal</span> </span>&#123;</span><br><span class="line">    constructor(name) &#123;</span><br><span class="line">        <span class="keyword">super</span>(name);</span><br><span class="line">        console.log(<span class="keyword">this</span>.name);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h3 id="抽象类"><a href="#抽象类" class="headerlink" title="抽象类"></a>抽象类</h3><p><strong>abstract</strong> 用于定义抽象类和其中的抽象方法。</p>
<p>什么是抽象类？</p>
<p>首先，抽象类是不允许被实例化的：</p>
<figure class="highlight smali"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">abstract class Animal &#123;</span><br><span class="line">   <span class="keyword"> public</span> name;</span><br><span class="line">   <span class="keyword"> public</span><span class="keyword"> constructor</span>(name) &#123;</span><br><span class="line">        this.name = name;</span><br><span class="line">    &#125;</span><br><span class="line">   <span class="keyword"> public</span><span class="keyword"> abstract</span> sayHi();</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">let a =<span class="built_in"> new </span>Animal('Jack');</span><br><span class="line"></span><br><span class="line">// index.ts(9,11): error TS2511: Cannot create an<span class="built_in"> instance </span>of the<span class="keyword"> abstract</span> class 'Animal'.</span><br></pre></td></tr></table></figure>
<p>上面的例子中，我们定义了一个抽象类 Animal，并且定义了一个抽象方法 sayHi。在实例化抽象类的时候报错了。</p>
<p>其次，抽象类中的抽象方法必须被子类实现：</p>
<figure class="highlight scala"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">abstract</span> <span class="class"><span class="keyword">class</span> <span class="title">Animal</span> </span>&#123;</span><br><span class="line">    public name;</span><br><span class="line">    public constructor(name) &#123;</span><br><span class="line">        <span class="keyword">this</span>.name = name;</span><br><span class="line">    &#125;</span><br><span class="line">    public <span class="keyword">abstract</span> sayHi();</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Cat</span> <span class="keyword">extends</span> <span class="title">Animal</span> </span>&#123;</span><br><span class="line">    public eat() &#123;</span><br><span class="line">        console.log(`$&#123;<span class="keyword">this</span>.name&#125; is eating.`);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">let cat = <span class="keyword">new</span> <span class="type">Cat</span>(<span class="symbol">'To</span>m');</span><br><span class="line"></span><br><span class="line"><span class="comment">// index.ts(9,7): error TS2515: Non-abstract class 'Cat' does not implement inherited abstract member 'sayHi' from class 'Animal'.</span></span><br></pre></td></tr></table></figure>
<p>上面的例子中，我们定义了一个类 Cat 继承了抽象类 Animal，但是没有实现抽象方法 sayHi，所以编译报错了。</p>
<p>下面是一个正确使用抽象类的例子：</p>
<figure class="highlight scala"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">abstract</span> <span class="class"><span class="keyword">class</span> <span class="title">Animal</span> </span>&#123;</span><br><span class="line">    public name;</span><br><span class="line">    public constructor(name) &#123;</span><br><span class="line">        <span class="keyword">this</span>.name = name;</span><br><span class="line">    &#125;</span><br><span class="line">    public <span class="keyword">abstract</span> sayHi();</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Cat</span> <span class="keyword">extends</span> <span class="title">Animal</span> </span>&#123;</span><br><span class="line">    public sayHi() &#123;</span><br><span class="line">        console.log(`<span class="type">Meow</span>, <span class="type">My</span> name is $&#123;<span class="keyword">this</span>.name&#125;`);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">let cat = <span class="keyword">new</span> <span class="type">Cat</span>(<span class="symbol">'To</span>m');</span><br></pre></td></tr></table></figure>
<p>上面的例子中，我们实现了抽象方法 sayHi，编译通过了。</p>
<p>需要注意的是，即使是抽象方法，TypeScript 的编译结果中，仍然会存在这个类，上面的代码的编译结果是：</p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> __extends = (<span class="keyword">this</span> &amp;&amp; <span class="keyword">this</span>.__extends) || <span class="function"><span class="keyword">function</span> (<span class="params">d, b</span>) </span>&#123;</span><br><span class="line">    <span class="keyword">for</span> (<span class="keyword">var</span> p <span class="keyword">in</span> b) <span class="keyword">if</span> (b.hasOwnProperty(p)) d[p] = b[p];</span><br><span class="line">    <span class="function"><span class="keyword">function</span> <span class="title">__</span>(<span class="params"></span>) </span>&#123; <span class="keyword">this</span>.constructor = d; &#125;</span><br><span class="line">    d.prototype = b === <span class="literal">null</span> ? <span class="built_in">Object</span>.create(b) : (__.prototype = b.prototype, <span class="keyword">new</span> __());</span><br><span class="line">&#125;;</span><br><span class="line"><span class="keyword">var</span> Animal = (<span class="function"><span class="keyword">function</span> (<span class="params"></span>) </span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">function</span> <span class="title">Animal</span>(<span class="params">name</span>) </span>&#123;</span><br><span class="line">        <span class="keyword">this</span>.name = name;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> Animal;</span><br><span class="line">&#125;());</span><br><span class="line"><span class="keyword">var</span> Cat = (<span class="function"><span class="keyword">function</span> (<span class="params">_super</span>) </span>&#123;</span><br><span class="line">    __extends(Cat, _super);</span><br><span class="line">    <span class="function"><span class="keyword">function</span> <span class="title">Cat</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">        _super.apply(<span class="keyword">this</span>, <span class="built_in">arguments</span>);</span><br><span class="line">    &#125;</span><br><span class="line">    Cat.prototype.sayHi = <span class="function"><span class="keyword">function</span> (<span class="params"></span>) </span>&#123;</span><br><span class="line">        <span class="built_in">console</span>.log(<span class="string">'Meow, My name is '</span> + <span class="keyword">this</span>.name);</span><br><span class="line">    &#125;;</span><br><span class="line">    <span class="keyword">return</span> Cat;</span><br><span class="line">&#125;(Animal));</span><br><span class="line"><span class="keyword">var</span> cat = <span class="keyword">new</span> Cat(<span class="string">'Tom'</span>);</span><br></pre></td></tr></table></figure>
<h3 id="类的类型"><a href="#类的类型" class="headerlink" title="类的类型"></a>类的类型</h3><p>给类加上 TypeScript 的类型很简单，与接口类似：</p>
<figure class="highlight typescript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> Animal &#123;</span><br><span class="line">    name: <span class="built_in">string</span>;</span><br><span class="line">    <span class="keyword">constructor</span>(<span class="params">name: <span class="built_in">string</span></span>) &#123;</span><br><span class="line">        <span class="keyword">this</span>.name = name;</span><br><span class="line">    &#125;</span><br><span class="line">    sayHi(): <span class="built_in">string</span> &#123;</span><br><span class="line">      <span class="keyword">return</span> <span class="string">`My name is <span class="subst">$&#123;<span class="keyword">this</span>.name&#125;</span>`</span>;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> a: Animal = <span class="keyword">new</span> Animal(<span class="string">'Jack'</span>);</span><br><span class="line"><span class="built_in">console</span>.log(a.sayHi()); <span class="comment">// My name is Jack</span></span><br></pre></td></tr></table></figure>
<h1 id="类与接口"><a href="#类与接口" class="headerlink" title="类与接口"></a>类与接口</h1><p>之前学习过，接口（Interfaces）可以用于对「对象的形状（Shape）」进行描述。</p>
<p>这一章主要介绍接口的另一个用途，对类的一部分行为进行抽象。</p>
<h2 id="类实现接口"><a href="#类实现接口" class="headerlink" title="类实现接口"></a>类实现接口</h2><p>实现（implements）是面向对象中的一个重要概念。一般来讲，一个类只能继承自另一个类，有时候不同类之间可以有一些共有的特性，这时候就可以把特性提取成接口（interfaces），用 implements 关键字来实现。这个特性大大提高了面向对象的灵活性。</p>
<p>举例来说，门是一个类，防盗门是门的子类。如果防盗门有一个报警器的功能，我们可以简单的给防盗门添加一个报警方法。这时候如果有另一个类，车，也有报警器的功能，就可以考虑把报警器提取出来，作为一个接口，防盗门和车都去实现它：</p>
<figure class="highlight scala"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line">interface <span class="type">Alarm</span> &#123;</span><br><span class="line">    alert();</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Door</span> </span>&#123;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">SecurityDoor</span> <span class="keyword">extends</span> <span class="title">Door</span> <span class="title">implements</span> <span class="title">Alarm</span> </span>&#123;</span><br><span class="line">    alert() &#123;</span><br><span class="line">        console.log(<span class="symbol">'SecurityDoor</span> alert');</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Car</span> <span class="title">implements</span> <span class="title">Alarm</span> </span>&#123;</span><br><span class="line">    alert() &#123;</span><br><span class="line">        console.log(<span class="symbol">'Car</span> alert');</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>一个类可以实现多个接口：</p>
<figure class="highlight less"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="selector-tag">interface</span> <span class="selector-tag">Alarm</span> &#123;</span><br><span class="line">    <span class="selector-tag">alert</span>();</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="selector-tag">interface</span> <span class="selector-tag">Light</span> &#123;</span><br><span class="line">    <span class="selector-tag">lightOn</span>();</span><br><span class="line">    <span class="selector-tag">lightOff</span>();</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="selector-tag">class</span> <span class="selector-tag">Car</span> <span class="selector-tag">implements</span> <span class="selector-tag">Alarm</span>, <span class="selector-tag">Light</span> &#123;</span><br><span class="line">    <span class="selector-tag">alert</span>() &#123;</span><br><span class="line">        <span class="selector-tag">console</span><span class="selector-class">.log</span>(<span class="string">'Car alert'</span>);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="selector-tag">lightOn</span>() &#123;</span><br><span class="line">        <span class="selector-tag">console</span><span class="selector-class">.log</span>(<span class="string">'Car light on'</span>);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="selector-tag">lightOff</span>() &#123;</span><br><span class="line">        <span class="selector-tag">console</span><span class="selector-class">.log</span>(<span class="string">'Car light off'</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>上例中，Car 实现了 Alarm 和 Light 接口，既能报警，也能开关车灯。</p>
<h2 id="接口继承接口"><a href="#接口继承接口" class="headerlink" title="接口继承接口"></a>接口继承接口</h2><p>接口与接口之间可以是继承关系：</p>
<figure class="highlight routeros"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">interface Alarm &#123;</span><br><span class="line">    alert();</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">interface LightableAlarm extends Alarm &#123;</span><br><span class="line">    lightOn();</span><br><span class="line">    lightOff();</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>上例中，我们使用 extends 使 LightableAlarm 继承 Alarm。</p>
<h2 id="接口继承类"><a href="#接口继承类" class="headerlink" title="接口继承类"></a>接口继承类</h2><p>接口也可以继承类：</p>
<figure class="highlight groovy"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Point</span> &#123;</span></span><br><span class="line"><span class="symbol">    x:</span> number;</span><br><span class="line"><span class="symbol">    y:</span> number;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">interface</span> <span class="title">Point3d</span> <span class="keyword">extends</span> <span class="title">Point</span> &#123;</span></span><br><span class="line"><span class="symbol">    z:</span> number;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">let <span class="string">point3d:</span> Point3d = &#123;<span class="string">x:</span> <span class="number">1</span>, <span class="string">y:</span> <span class="number">2</span>, <span class="string">z:</span> <span class="number">3</span>&#125;;</span><br></pre></td></tr></table></figure>
<h3 id="混合类型"><a href="#混合类型" class="headerlink" title="混合类型"></a>混合类型</h3><p>之前学习过，可以使用接口的方式来定义一个函数需要符合的形状：</p>
<figure class="highlight typescript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">interface</span> SearchFunc &#123;</span><br><span class="line">    (source: <span class="built_in">string</span>, subString: <span class="built_in">string</span>): <span class="built_in">boolean</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> mySearch: SearchFunc;</span><br><span class="line">mySearch = <span class="function"><span class="keyword">function</span>(<span class="params">source: <span class="built_in">string</span>, subString: <span class="built_in">string</span></span>) </span>&#123;</span><br><span class="line">    <span class="keyword">return</span> source.search(subString) !== <span class="number">-1</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>有时候，一个函数还可以有自己的属性和方法：</p>
<figure class="highlight typescript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">interface</span> Counter &#123;</span><br><span class="line">    (start: <span class="built_in">number</span>): <span class="built_in">string</span>;</span><br><span class="line">    interval: <span class="built_in">number</span>;</span><br><span class="line">    reset(): <span class="built_in">void</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">getCounter</span>(<span class="params"></span>): <span class="title">Counter</span> </span>&#123;</span><br><span class="line">    <span class="keyword">let</span> counter = &lt;Counter&gt;<span class="function"><span class="keyword">function</span> (<span class="params">start: <span class="built_in">number</span></span>) </span>&#123; &#125;;</span><br><span class="line">    counter.interval = <span class="number">123</span>;</span><br><span class="line">    counter.reset = <span class="function"><span class="keyword">function</span> (<span class="params"></span>) </span>&#123; &#125;;</span><br><span class="line">    <span class="keyword">return</span> counter;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> c = getCounter();</span><br><span class="line">c(<span class="number">10</span>);</span><br><span class="line">c.reset();</span><br><span class="line">c.interval = <span class="number">5.0</span>;</span><br></pre></td></tr></table></figure>
<h1 id="泛型"><a href="#泛型" class="headerlink" title="泛型"></a>泛型</h1><p>泛型（Generics）是指在定义函数、接口或类的时候，不预先指定具体的类型，而在使用的时候再指定类型的一种特性。</p>
<h2 id="简单的例子-4"><a href="#简单的例子-4" class="headerlink" title="简单的例子"></a>简单的例子</h2><p>首先，我们来实现一个函数 createArray，它可以创建一个指定长度的数组，同时将每一项都填充一个默认值：</p>
<figure class="highlight julia"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">function</span> createArray(length: number, value: any): <span class="built_in">Array</span>&lt;any&gt; &#123;</span><br><span class="line">    <span class="keyword">let</span> result = [];</span><br><span class="line">    <span class="keyword">for</span> (<span class="keyword">let</span> i = <span class="number">0</span>; i &lt; length; i++) &#123;</span><br><span class="line">        result[i] = value;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> result;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">createArray(<span class="number">3</span>, <span class="string">'x'</span>); // [<span class="string">'x'</span>, <span class="string">'x'</span>, <span class="string">'x'</span>]</span><br></pre></td></tr></table></figure>
<p>上例中，我们使用了之前提到过的数组泛型来定义返回值的类型。</p>
<p>这段代码编译不会报错，但是一个显而易见的缺陷是，它并没有准确的定义返回值的类型：</p>
<p><code>Array&lt;any&gt;</code> 允许数组的每一项都为任意类型。但是我们预期的是，数组中每一项都应该是输入的 value 的类型。</p>
<p>这时候，泛型就派上用场了：</p>
<figure class="highlight r"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">function</span> createArray&lt;<span class="literal">T</span>&gt;(length: number, value: <span class="literal">T</span>): Array&lt;<span class="literal">T</span>&gt; &#123;</span><br><span class="line">    let result: <span class="literal">T</span>[] = [];</span><br><span class="line">    <span class="keyword">for</span> (let i = <span class="number">0</span>; i &lt; length; i++) &#123;</span><br><span class="line">        result[i] = value;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> result;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">createArray&lt;string&gt;(<span class="number">3</span>, <span class="string">'x'</span>); // [<span class="string">'x'</span>, <span class="string">'x'</span>, <span class="string">'x'</span>]</span><br></pre></td></tr></table></figure>
<p>上例中，我们在函数名后添加了 <t>，其中 T 用来指代任意输入的类型，在后面的输入 value: T 和输出 Array<t> 中即可使用了。</t></t></p>
<p>接着在调用的时候，可以指定它具体的类型为 string。当然，也可以不手动指定，而让类型推论自动推算出来：</p>
<figure class="highlight r"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">function</span> createArray&lt;<span class="literal">T</span>&gt;(length: number, value: <span class="literal">T</span>): Array&lt;<span class="literal">T</span>&gt; &#123;</span><br><span class="line">    let result: <span class="literal">T</span>[] = [];</span><br><span class="line">    <span class="keyword">for</span> (let i = <span class="number">0</span>; i &lt; length; i++) &#123;</span><br><span class="line">        result[i] = value;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> result;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">createArray(<span class="number">3</span>, <span class="string">'x'</span>); // [<span class="string">'x'</span>, <span class="string">'x'</span>, <span class="string">'x'</span>]</span><br></pre></td></tr></table></figure>
<h2 id="多个类型参数"><a href="#多个类型参数" class="headerlink" title="多个类型参数"></a>多个类型参数</h2><p>定义泛型的时候，可以一次定义多个类型参数：</p>
<figure class="highlight prolog"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">function swap&lt;<span class="symbol">T</span>, <span class="symbol">U</span>&gt;(tuple: [<span class="symbol">T</span>, <span class="symbol">U</span>]): [<span class="symbol">U</span>, <span class="symbol">T</span>] &#123;</span><br><span class="line">    return [tuple[<span class="number">1</span>], tuple[<span class="number">0</span>]];</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">swap([<span class="number">7</span>, <span class="string">'seven'</span>]); // [<span class="string">'seven'</span>, <span class="number">7</span>]</span><br></pre></td></tr></table></figure>
<p>上例中，我们定义了一个 swap 函数，用来交换输入的元组。</p>
<h2 id="泛型约束"><a href="#泛型约束" class="headerlink" title="泛型约束"></a>泛型约束</h2><p>在函数内部使用泛型变量的时候，由于事先不知道它是哪种类型，所以不能随意的操作它的属性或方法：</p>
<figure class="highlight lua"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">loggingIdentity</span>&lt;<span class="title">T</span>&gt;<span class="params">(arg: T)</span></span>: T &#123;</span><br><span class="line">    console.<span class="built_in">log</span>(<span class="built_in">arg</span>.length);</span><br><span class="line">    <span class="keyword">return</span> <span class="built_in">arg</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">// index.ts(<span class="number">2</span>,<span class="number">19</span>): <span class="built_in">error</span> TS2339: Property <span class="string">'length'</span> does <span class="keyword">not</span> exist on <span class="built_in">type</span> <span class="string">'T'</span>.</span><br></pre></td></tr></table></figure>
<p>上例中，泛型 T 不一定包含属性 length，所以编译的时候报错了。</p>
<p>这时，我们可以对泛型进行约束，只允许这个函数传入那些包含 length 属性的变量。这就是泛型约束：</p>
<figure class="highlight fortran"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">interface</span> Lengthwise &#123;</span><br><span class="line">    length: <span class="keyword">number</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">function</span></span> loggingIdentity&lt;T <span class="keyword">extends</span> Lengthwise&gt;(arg: T): T &#123;</span><br><span class="line">    console.<span class="built_in">log</span>(arg.length);</span><br><span class="line">    <span class="keyword">return</span> arg;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>上例中，我们使用了 extends 约束了泛型 T 必须符合接口 Lengthwise 的形状，也就是必须包含 length 属性。</p>
<p>此时如果调用 loggingIdentity 的时候，传入的 arg 不包含 length，那么在编译阶段就会报错了：</p>
<figure class="highlight lua"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line">interface Lengthwise &#123;</span><br><span class="line">    length: number;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">loggingIdentity</span>&lt;<span class="title">T</span> <span class="title">extends</span> <span class="title">Lengthwise</span>&gt;<span class="params">(arg: T)</span></span>: T &#123;</span><br><span class="line">    console.<span class="built_in">log</span>(<span class="built_in">arg</span>.length);</span><br><span class="line">    <span class="keyword">return</span> <span class="built_in">arg</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">loggingIdentity(<span class="number">7</span>);</span><br><span class="line"></span><br><span class="line">// index.ts(<span class="number">10</span>,<span class="number">17</span>): <span class="built_in">error</span> TS2345: Argument of <span class="built_in">type</span> <span class="string">'7'</span> is <span class="keyword">not</span> assignable to parameter of <span class="built_in">type</span> <span class="string">'Lengthwise'</span>.</span><br></pre></td></tr></table></figure>
<p>多个类型参数之间也可以互相约束：</p>
<figure class="highlight groovy"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">function copyFields&lt;T <span class="keyword">extends</span> U, U&gt;(<span class="string">target:</span> T, <span class="string">source:</span> U): T &#123;</span><br><span class="line">    <span class="keyword">for</span> (let id <span class="keyword">in</span> source) &#123;</span><br><span class="line">        target[id] = (&lt;T&gt;source)[id];</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> target;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">let x = &#123; <span class="string">a:</span> <span class="number">1</span>, <span class="string">b:</span> <span class="number">2</span>, <span class="string">c:</span> <span class="number">3</span>, <span class="string">d:</span> <span class="number">4</span> &#125;;</span><br><span class="line"></span><br><span class="line">copyFields(x, &#123; <span class="string">b:</span> <span class="number">10</span>, <span class="string">d:</span> <span class="number">20</span> &#125;);</span><br></pre></td></tr></table></figure>
<p>上例中，我们使用了两个类型参数，其中要求 T 继承 U，这样就保证了 U 上不会出现 T 中不存在的字段。</p>
<h2 id="泛型接口"><a href="#泛型接口" class="headerlink" title="泛型接口"></a>泛型接口</h2><p>之前学习过，可以使用接口的方式来定义一个函数需要符合的形状：</p>
<figure class="highlight typescript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">interface</span> SearchFunc &#123;</span><br><span class="line">  (source: <span class="built_in">string</span>, subString: <span class="built_in">string</span>): <span class="built_in">boolean</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> mySearch: SearchFunc;</span><br><span class="line">mySearch = <span class="function"><span class="keyword">function</span>(<span class="params">source: <span class="built_in">string</span>, subString: <span class="built_in">string</span></span>) </span>&#123;</span><br><span class="line">    <span class="keyword">return</span> source.search(subString) !== <span class="number">-1</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>当然也可以使用含有泛型的接口来定义函数的形状：</p>
<figure class="highlight r"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line">interface CreateArrayFunc &#123;</span><br><span class="line">    &lt;<span class="literal">T</span>&gt;(length: number, value: <span class="literal">T</span>): Array&lt;<span class="literal">T</span>&gt;;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">let createArray: CreateArrayFunc;</span><br><span class="line">createArray = <span class="keyword">function</span>&lt;<span class="literal">T</span>&gt;(length: number, value: <span class="literal">T</span>): Array&lt;<span class="literal">T</span>&gt; &#123;</span><br><span class="line">    let result: <span class="literal">T</span>[] = [];</span><br><span class="line">    <span class="keyword">for</span> (let i = <span class="number">0</span>; i &lt; length; i++) &#123;</span><br><span class="line">        result[i] = value;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> result;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">createArray(<span class="number">3</span>, <span class="string">'x'</span>); // [<span class="string">'x'</span>, <span class="string">'x'</span>, <span class="string">'x'</span>]</span><br></pre></td></tr></table></figure>
<p>进一步，我们可以把泛型参数提前到接口名上：<br><figure class="highlight typescript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">interface</span> CreateArrayFunc&lt;T&gt; &#123;</span><br><span class="line">    (length: <span class="built_in">number</span>, value: T): <span class="built_in">Array</span>&lt;T&gt;;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> createArray: CreateArrayFunc&lt;<span class="built_in">any</span>&gt;;</span><br><span class="line">createArray = <span class="function"><span class="keyword">function</span>&lt;<span class="title">T</span>&gt;(<span class="params">length: <span class="built_in">number</span>, value: T</span>): <span class="title">Array</span>&lt;<span class="title">T</span>&gt; </span>&#123;</span><br><span class="line">    <span class="keyword">let</span> result: T[] = [];</span><br><span class="line">    <span class="keyword">for</span> (<span class="keyword">let</span> i = <span class="number">0</span>; i &lt; length; i++) &#123;</span><br><span class="line">        result[i] = value;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> result;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">createArray(<span class="number">3</span>, <span class="string">'x'</span>); <span class="comment">// ['x', 'x', 'x']</span></span><br></pre></td></tr></table></figure></p>
<p>注意，此时在使用泛型接口的时候，需要定义泛型的类型。</p>
<h2 id="泛型类"><a href="#泛型类" class="headerlink" title="泛型类"></a>泛型类</h2><p>与泛型接口类似，泛型也可以用于类的类型定义中：</p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">GenericNumber</span>&lt;<span class="title">T</span>&gt; </span>&#123;</span><br><span class="line">    zeroValue: T;</span><br><span class="line">    add: <span class="function">(<span class="params">x: T, y: T</span>) =&gt;</span> T;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> myGenericNumber = <span class="keyword">new</span> GenericNumber&lt;number&gt;();</span><br><span class="line">myGenericNumber.zeroValue = <span class="number">0</span>;</span><br><span class="line">myGenericNumber.add = <span class="function"><span class="keyword">function</span>(<span class="params">x, y</span>) </span>&#123; <span class="keyword">return</span> x + y; &#125;;</span><br></pre></td></tr></table></figure>
<h2 id="泛型参数的默认类型"><a href="#泛型参数的默认类型" class="headerlink" title="泛型参数的默认类型"></a>泛型参数的默认类型</h2><p>在 TypeScript 2.3 以后，我们可以为泛型中的类型参数指定默认类型。当使用泛型时没有在代码中直接指定类型参数，从实际值参数中也无法推测出时，这个默认类型就会起作用。</p>
<figure class="highlight matlab"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">createArray</span>&lt;<span class="title">T</span> = <span class="title">string</span>&gt;<span class="params">(length: number, value: T)</span>: <span class="title">Array</span>&lt;<span class="title">T</span>&gt; &#123;</span></span><br><span class="line">    let result: T[] = [];</span><br><span class="line">    <span class="keyword">for</span> (let <span class="built_in">i</span> = <span class="number">0</span>; <span class="built_in">i</span> &lt; <span class="built_in">length</span>; <span class="built_in">i</span>++) &#123;</span><br><span class="line">        result[<span class="built_in">i</span>] = value;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> result;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h1 id="声明合并"><a href="#声明合并" class="headerlink" title="声明合并"></a>声明合并</h1><p>如果定义了两个相同名字的函数、接口或类，那么它们会合并成一个类型：</p>
<h2 id="函数的合并"><a href="#函数的合并" class="headerlink" title="函数的合并"></a>函数的合并</h2><p>之前学习过，我们可以使用重载定义多个函数类型：</p>
<figure class="highlight xquery"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">function</span><span class="built_in"> reverse</span>(x:<span class="built_in"> number</span>):<span class="built_in"> number</span>;</span><br><span class="line"><span class="keyword">function</span><span class="built_in"> reverse</span>(x:<span class="built_in"> string</span>):<span class="built_in"> string</span>;</span><br><span class="line"><span class="keyword">function</span><span class="built_in"> reverse</span>(x:<span class="built_in"> number</span> |<span class="built_in"> string</span>):<span class="built_in"> number</span> |<span class="built_in"> string</span> &#123;</span><br><span class="line">    <span class="keyword">if</span> (typeof x === <span class="string">'number'</span>) &#123;</span><br><span class="line">        <span class="keyword">return</span> Number(x.toString().split(<span class="string">''</span>)<span class="built_in">.reverse</span>().join(<span class="string">''</span>));</span><br><span class="line">    &#125; <span class="keyword">else</span> <span class="keyword">if</span> (typeof x === <span class="string">'string'</span>) &#123;</span><br><span class="line">        <span class="keyword">return</span> x.split(<span class="string">''</span>)<span class="built_in">.reverse</span>().join(<span class="string">''</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h2 id="接口的合并"><a href="#接口的合并" class="headerlink" title="接口的合并"></a>接口的合并</h2><p>接口中的属性在合并时会简单的合并到一个接口中：</p>
<figure class="highlight routeros"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">interface Alarm &#123;</span><br><span class="line">    price: number;</span><br><span class="line">&#125;</span><br><span class="line">interface Alarm &#123;</span><br><span class="line">    weight: number;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>相当于：</p>
<figure class="highlight css"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="selector-tag">interface</span> <span class="selector-tag">Alarm</span> &#123;</span><br><span class="line">    <span class="attribute">price</span>: number;</span><br><span class="line">    <span class="attribute">weight</span>: number;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>注意，合并的属性的类型必须是唯一的：</p>
<figure class="highlight typescript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">interface</span> Alarm &#123;</span><br><span class="line">    price: <span class="built_in">number</span>;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">interface</span> Alarm &#123;</span><br><span class="line">    price: <span class="built_in">number</span>;  <span class="comment">// 虽然重复了，但是类型都是 `number`，所以不会报错</span></span><br><span class="line">    weight: <span class="built_in">number</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<figure class="highlight typescript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">interface</span> Alarm &#123;</span><br><span class="line">    price: <span class="built_in">number</span>;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">interface</span> Alarm &#123;</span><br><span class="line">    price: <span class="built_in">string</span>;  <span class="comment">// 类型不一致，会报错</span></span><br><span class="line">    weight: <span class="built_in">number</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// index.ts(5,3): error TS2403: Subsequent variable declarations must have the same type.  Variable 'price' must be of type 'number', but here has type 'string'.</span></span><br></pre></td></tr></table></figure>
<p>接口中方法的合并，与函数的合并一样：</p>
<figure class="highlight typescript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">interface</span> Alarm &#123;</span><br><span class="line">    price: <span class="built_in">number</span>;</span><br><span class="line">    alert(s: <span class="built_in">string</span>): <span class="built_in">string</span>;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">interface</span> Alarm &#123;</span><br><span class="line">    weight: <span class="built_in">number</span>;</span><br><span class="line">    alert(s: <span class="built_in">string</span>, n: <span class="built_in">number</span>): <span class="built_in">string</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>相当于：</p>
<figure class="highlight typescript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">interface</span> Alarm &#123;</span><br><span class="line">    price: <span class="built_in">number</span>;</span><br><span class="line">    weight: <span class="built_in">number</span>;</span><br><span class="line">    alert(s: <span class="built_in">string</span>): <span class="built_in">string</span>;</span><br><span class="line">    alert(s: <span class="built_in">string</span>, n: <span class="built_in">number</span>): <span class="built_in">string</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h2 id="类的合并"><a href="#类的合并" class="headerlink" title="类的合并"></a>类的合并</h2><p>类的合并与接口的合并规则一致。</p>

      
    </div>
    
    
    

    

    

    

    <footer class="post-footer">
      
        <div class="post-tags">
          
            <a href="/blog/tags/进阶/" rel="tag"># 进阶</a>
          
        </div>
      

      
      
      

      
        <div class="post-nav">
          <div class="post-nav-next post-nav-item">
            
              <a href="/blog/2018/09/27/JavaScript-模块化模式/" rel="next" title="JavaScript 模块化模式">
                <i class="fa fa-chevron-left"></i> JavaScript 模块化模式
              </a>
            
          </div>

          <span class="post-nav-divider"></span>

          <div class="post-nav-prev post-nav-item">
            
              <a href="/blog/2018/09/27/javascript-单例模式/" rel="prev" title="javascript 单例模式">
                javascript 单例模式 <i class="fa fa-chevron-right"></i>
              </a>
            
          </div>
        </div>
      

      
      
    </footer>
  </div>
  
  
  
  </article>



    <div class="post-spread">
      
    </div>
  </div>


          </div>
          


          

  



        </div>
        
          
  
  <div class="sidebar-toggle">
    <div class="sidebar-toggle-line-wrap">
      <span class="sidebar-toggle-line sidebar-toggle-line-first"></span>
      <span class="sidebar-toggle-line sidebar-toggle-line-middle"></span>
      <span class="sidebar-toggle-line sidebar-toggle-line-last"></span>
    </div>
  </div>

  <aside id="sidebar" class="sidebar">
    
    <div class="sidebar-inner">

      

      
        <ul class="sidebar-nav motion-element">
          <li class="sidebar-nav-toc sidebar-nav-active" data-target="post-toc-wrap">
            Table of Contents
          </li>
          <li class="sidebar-nav-overview" data-target="site-overview-wrap">
            Overview
          </li>
        </ul>
      

      <section class="site-overview-wrap sidebar-panel">
        <div class="site-overview">
          <div class="site-author motion-element" itemprop="author" itemscope itemtype="http://schema.org/Person">
            
              <p class="site-author-name" itemprop="name">lhweb</p>
              <p class="site-description motion-element" itemprop="description"></p>
          </div>

          <nav class="site-state motion-element">

            
              <div class="site-state-item site-state-posts">
              
                <a href="/blog/archives/">
              
                  <span class="site-state-item-count">39</span>
                  <span class="site-state-item-name">posts</span>
                </a>
              </div>
            

            
              
              
              <div class="site-state-item site-state-categories">
                <a href="/blog/categories/index.html">
                  <span class="site-state-item-count">6</span>
                  <span class="site-state-item-name">categories</span>
                </a>
              </div>
            

            
              
              
              <div class="site-state-item site-state-tags">
                <a href="/blog/tags/index.html">
                  <span class="site-state-item-count">25</span>
                  <span class="site-state-item-name">tags</span>
                </a>
              </div>
            

          </nav>

          
            <div class="feed-link motion-element">
              <a href="/blog/atom.xml" rel="alternate">
                <i class="fa fa-rss"></i>
                RSS
              </a>
            </div>
          

          

          
          

          
          

          

        </div>
      </section>

      
      <!--noindex-->
        <section class="post-toc-wrap motion-element sidebar-panel sidebar-panel-active">
          <div class="post-toc">

            
              
            

            
              <div class="post-toc-content"><ol class="nav"><li class="nav-item nav-level-1"><a class="nav-link" href="#类型别名"><span class="nav-number">1.</span> <span class="nav-text">类型别名</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#简单的例子"><span class="nav-number">1.1.</span> <span class="nav-text">简单的例子</span></a></li></ol></li><li class="nav-item nav-level-1"><a class="nav-link" href="#字符串字面量类型"><span class="nav-number">2.</span> <span class="nav-text">字符串字面量类型</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#简单的例子-1"><span class="nav-number">2.1.</span> <span class="nav-text">简单的例子</span></a></li></ol></li><li class="nav-item nav-level-1"><a class="nav-link" href="#元组"><span class="nav-number">3.</span> <span class="nav-text">元组</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#简单的例子-2"><span class="nav-number">3.1.</span> <span class="nav-text">简单的例子</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#越界的元素"><span class="nav-number">3.2.</span> <span class="nav-text">越界的元素</span></a></li></ol></li><li class="nav-item nav-level-1"><a class="nav-link" href="#枚举"><span class="nav-number">4.</span> <span class="nav-text">枚举</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#简单的例子-3"><span class="nav-number">4.1.</span> <span class="nav-text">简单的例子</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#手动赋值"><span class="nav-number">4.2.</span> <span class="nav-text">手动赋值</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#常数项和计算所得项"><span class="nav-number">4.3.</span> <span class="nav-text">常数项和计算所得项</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#常数枚举"><span class="nav-number">4.4.</span> <span class="nav-text">常数枚举</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#外部枚举"><span class="nav-number">4.5.</span> <span class="nav-text">外部枚举</span></a></li></ol></li><li class="nav-item nav-level-1"><a class="nav-link" href="#类"><span class="nav-number">5.</span> <span class="nav-text">类</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#类的概念"><span class="nav-number">5.1.</span> <span class="nav-text">类的概念</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#ES6-中类的用法"><span class="nav-number">5.2.</span> <span class="nav-text">ES6 中类的用法</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#属性和方法"><span class="nav-number">5.2.1.</span> <span class="nav-text">属性和方法</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#类的继承"><span class="nav-number">5.2.2.</span> <span class="nav-text">类的继承</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#存取器"><span class="nav-number">5.2.3.</span> <span class="nav-text">存取器</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#静态方法"><span class="nav-number">5.2.4.</span> <span class="nav-text">静态方法</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#ES7-中类的用法"><span class="nav-number">5.3.</span> <span class="nav-text">ES7 中类的用法</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#实例属性"><span class="nav-number">5.3.1.</span> <span class="nav-text">实例属性</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#静态属性"><span class="nav-number">5.3.2.</span> <span class="nav-text">静态属性</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#TypeScript-中类的用法"><span class="nav-number">5.4.</span> <span class="nav-text">TypeScript 中类的用法</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#public-private-和-protected"><span class="nav-number">5.4.1.</span> <span class="nav-text">public private 和 protected</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#抽象类"><span class="nav-number">5.4.2.</span> <span class="nav-text">抽象类</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#类的类型"><span class="nav-number">5.4.3.</span> <span class="nav-text">类的类型</span></a></li></ol></li></ol></li><li class="nav-item nav-level-1"><a class="nav-link" href="#类与接口"><span class="nav-number">6.</span> <span class="nav-text">类与接口</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#类实现接口"><span class="nav-number">6.1.</span> <span class="nav-text">类实现接口</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#接口继承接口"><span class="nav-number">6.2.</span> <span class="nav-text">接口继承接口</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#接口继承类"><span class="nav-number">6.3.</span> <span class="nav-text">接口继承类</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#混合类型"><span class="nav-number">6.3.1.</span> <span class="nav-text">混合类型</span></a></li></ol></li></ol></li><li class="nav-item nav-level-1"><a class="nav-link" href="#泛型"><span class="nav-number">7.</span> <span class="nav-text">泛型</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#简单的例子-4"><span class="nav-number">7.1.</span> <span class="nav-text">简单的例子</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#多个类型参数"><span class="nav-number">7.2.</span> <span class="nav-text">多个类型参数</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#泛型约束"><span class="nav-number">7.3.</span> <span class="nav-text">泛型约束</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#泛型接口"><span class="nav-number">7.4.</span> <span class="nav-text">泛型接口</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#泛型类"><span class="nav-number">7.5.</span> <span class="nav-text">泛型类</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#泛型参数的默认类型"><span class="nav-number">7.6.</span> <span class="nav-text">泛型参数的默认类型</span></a></li></ol></li><li class="nav-item nav-level-1"><a class="nav-link" href="#声明合并"><span class="nav-number">8.</span> <span class="nav-text">声明合并</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#函数的合并"><span class="nav-number">8.1.</span> <span class="nav-text">函数的合并</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#接口的合并"><span class="nav-number">8.2.</span> <span class="nav-text">接口的合并</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#类的合并"><span class="nav-number">8.3.</span> <span class="nav-text">类的合并</span></a></li></ol></li></ol></div>
            

          </div>
        </section>
      <!--/noindex-->
      

      

    </div>
  </aside>


        
      </div>
    </main>

    <footer id="footer" class="footer">
      <div class="footer-inner">
        <div class="copyright">&copy; <span itemprop="copyrightYear">2019</span>
  <span class="with-love">
    <i class="fa fa-user"></i>
  </span>
  <span class="author" itemprop="copyrightHolder">lhweb</span>

  
</div>


  <div class="powered-by">Powered by <a class="theme-link" target="_blank" href="https://hexo.io">Hexo</a></div>



  <span class="post-meta-divider">|</span>



  <div class="theme-info">Theme &mdash; <a class="theme-link" target="_blank" href="https://github.com/iissnan/hexo-theme-next">NexT.Muse</a> v5.1.4</div>




        







        
      </div>
    </footer>

    
      <div class="back-to-top">
        <i class="fa fa-arrow-up"></i>
        
      </div>
    

    

  </div>

  

<script type="text/javascript">
  if (Object.prototype.toString.call(window.Promise) !== '[object Function]') {
    window.Promise = null;
  }
</script>









  












  
  
    <script type="text/javascript" src="/blog/lib/jquery/index.js?v=2.1.3"></script>
  

  
  
    <script type="text/javascript" src="/blog/lib/fastclick/lib/fastclick.min.js?v=1.0.6"></script>
  

  
  
    <script type="text/javascript" src="/blog/lib/jquery_lazyload/jquery.lazyload.js?v=1.9.7"></script>
  

  
  
    <script type="text/javascript" src="/blog/lib/velocity/velocity.min.js?v=1.2.1"></script>
  

  
  
    <script type="text/javascript" src="/blog/lib/velocity/velocity.ui.min.js?v=1.2.1"></script>
  

  
  
    <script type="text/javascript" src="/blog/lib/fancybox/source/jquery.fancybox.pack.js?v=2.1.5"></script>
  


  


  <script type="text/javascript" src="/blog/js/src/utils.js?v=5.1.4"></script>

  <script type="text/javascript" src="/blog/js/src/motion.js?v=5.1.4"></script>



  
  

  
  <script type="text/javascript" src="/blog/js/src/scrollspy.js?v=5.1.4"></script>
<script type="text/javascript" src="/blog/js/src/post-details.js?v=5.1.4"></script>



  


  <script type="text/javascript" src="/blog/js/src/bootstrap.js?v=5.1.4"></script>



  


  




	





  





  












  





  

  

  

  
  

  

  

  

</body>
</html>
